<?php

require_once 'Request.php';
require_once 'Validator.php';
require_once 'Controller.php';
require_once 'BoolValidator.php';
require_once 'TextValidator.php';
require_once 'EmailValidator.php';
require_once 'InputValidator.php';
require_once 'AbstractHelper.php';
require_once 'NumberValidator.php';

class FormValidator extends AbstractHelper implements Validator{

    private static $textMin1 = null;
    private static $textMin5 = null;
    private static $textMin10 = null;
    private static $textEmail = null;
    private static $number = null;
    private static $numberPositive = null;
    private static $bool = null;

    const TYPE_TEXT_MIN_1 = 0;
    const TYPE_TEXT_MIN_5 = 1;
    const TYPE_TEXT_MIN_10 = 2;
    const TYPE_TEXT_EMAIL = 3;
    const TYPE_NUMBER = 4;
    const TYPE_NUMBER_POSITIVE = 5;
    const TYPE_BOOL = 6;
    const VALUE_NOT_SET = 0;
    const VALUE_INVALID = 1;

    private $method;
    private $validators = array();
    private $detailedOutput = false;

    public function getMethod(){return $this->method;}

    public function setDetailedOutputEnabled($enabled){
        $this->detailedOutput = $enabled;
    }

    public static function _staticInitializer(){
        if(self::$textMin5 === null){
            self::$textMin1 = new TextValidator(1);
            self::$textMin5 = new TextValidator(5);
            self::$textMin10 = new TextValidator(10);
            self::$textEmail = new EmailValidator();
            self::$number = new NumberValidator(null);
            self::$numberPositive = new NumberValidator();
            self::$bool = new BoolValidator();
        }
    }

    public function __construct(Controller $owner = null, $method = Request::METHOD_POST){
        $this->method = $method;
        $this->owner = $owner;
    }


    public function registerInput($name, $type){
        Checker::checkString($name);
        if($type === self::TYPE_TEXT_MIN_1)$type = self::$textMin1;
        else if($type === self::TYPE_TEXT_MIN_5)$type = self::$textMin5;
        else if($type === self::TYPE_TEXT_MIN_10)$type = self::$textMin10;
        else if($type === self::TYPE_TEXT_EMAIL)$type = self::$textEmail;
        else if($type === self::TYPE_NUMBER)$type = self::$number;
        else if($type === self::TYPE_NUMBER_POSITIVE)$type = self::$numberPositive;
        else if($type === self::TYPE_BOOL)$type = self::$bool;
        else if(!($type instanceof InputValidator))
            throw new InvalidArgumentException("Invalid InputValidator instance");
        if($this->owner !== null && $this->method === Request::METHOD_GET)
            $this->owner->reserveParameter($name);
        $this->validators[$name] = $type;
    }

    public function validate(){
        if($this->owner != null)$request = $this->owner->getRequest();
        else $request = new Request();

        $da = $this->detailedOutput;
        if($da){
            $errors = array();
            $successes = array();
            $output = new stdClass();
            foreach($this->validators as $name => $validator){
                $value = $request->getParameter($name, $this->method);
                if($validator instanceof MatchValidator){
                    $match = $request->getParameter($validator->getMatchName(), $this->method);
                    $validator->setMatchValue($match);
                }
                if(($value === null && !($validator instanceof BoolValidator)) || !$validator->validate($value))
                    $errors[$name] = $value;
                else $successes[$name] = $value;
            }
            $output->errors = $errors;
            $output->successes = $successes;
            return $output;
        }
        //else
        foreach($this->validators as $name => $validator){
            $value = $request->getParameter($name, $this->method);
            if($value === null || !$validator->validate($value))
                return false;
        }
        return true;
    }

}
FormValidator::_staticInitializer();
?>
